#include <iostream>
#include "BaselineRandomWalk.h"

void BaseCrawler::nextStep()
{
    int nid = nodeToExplore();
    if (nid == -1)
      return;
    TVec<TInt> rec;
    network->getAllFollowers(nid, rec);
    network->getAllFollowees(nid, rec);
    for(TVec<TInt>::TIter i = rec.BegI(); i != rec.EndI(); i++)
      updateDiscoveredNode(i->Val);
    TIntPr p = network->evaluate();
    int totalCost = network->getTotalCost();
    //if(totalCost % 1000 == 0){
    nodeRecall.Add(TFltPr(network->getTotalCost(), double(p.Val1)));
    edgeRecall.Add(TFltPr(network->getTotalCost(), double(p.Val2)));
    //}
}

int BaselineRandomWalk::nodeToExplore() {
  if(accessibleNodesByRank.empty())
        return network->getTeleportNode();
  int retVal = accessibleNodesByRank.begin()->second;
  accessibleNodesByRank.erase(accessibleNodesByRank.begin());
  nodePointers.erase(retVal);
  return retVal;  
}

void BaselineRandomWalk::updateDiscoveredNode(int discoveredNode) {
  if(nodePointers.find(discoveredNode) == nodePointers.end()) {
    // Add to our accessibleNodes and assign random rank. Synchronize the maps
    pair<map<int,int>::iterator, bool> p = accessibleNodesByRank.insert(make_pair(rand(), discoveredNode));
    nodePointers[discoveredNode] = p.first;
  }
}

// For testing purpose
#ifdef BASELINE_RANDOMWALK_VS_TELEPORTER_TEST

#include <iostream>

int main(int argc, char* argv[]) {
    const int MAX_COST = 100;
    PNGraph G = TSnap::GenRndGnm<PNGraph>(1000,10000);
    PNEGraph Graph = TSnap::ConvertGraph<PNEGraph>(G);
    API *wapi = new API(Graph), *tapi = new API(Graph); //Actually, we need only one since BaselineRandomWalk constructor is passed by value
    BaselineRandomWalk walker(wapi), teleporter(tapi);
    walker.setCostLimit(MAX_COST);
    teleporter.setCostLimit(MAX_COST);
    while(walker.getTotalCost() < MAX_COST || 
        teleporter.getTotalCost() < MAX_COST) {
        walker.nextStep();
        TIntPr p = walker.evaluate();
        cout << "Walker cost used: " << walker.getTotalCost() << "  node recall: " << p.Val1  << endl;
        teleporter.nextStep();
        TIntPr p = teleporter.evaluate();
        cout << "Teleporter cost used: " << teleporter.getTotalCost() << "  node recall: " << p.Val1  << endl;
    }
    return 0;
}

#endif
